/**
 * forum
 * zhanjung
 */
package com.junhong.forum.stats;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.EJB;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Timeout;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import javax.interceptor.ExcludeDefaultInterceptors;

/**
 * @author zhanjung
 *         handle the thread votes and Rating
 * 
 */
@ExcludeDefaultInterceptors
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@Named
@ApplicationScoped
public class RatingCache {

	@EJB
	private CacheManager					hitManager;

	/* ------------instance Variable-------------- */
	private Map<CacheKey, AtomicInteger>	VOTE_CACHE	= new ConcurrentHashMap<CacheKey, AtomicInteger>();

	// private Map<CacheKey, AtomicInteger> RATING_CACHE = new
	// ConcurrentHashMap<CacheKey, AtomicInteger>();

	/* -------------business logic----------------- */
	/**
	 * No need to be synchronized, because using atomicinteger.
	 * 
	 * @param cacheKey
	 * @return
	 */
	@Lock(LockType.READ)
	public int incrementAndGet(CacheKey cacheKey) {
		return getVote(cacheKey).incrementAndGet();
		// voteNRating[1] = getRating(cacheKey.getId()).addAndGet(rating);
	}

	/**
	 * get the value only
	 * 
	 * @param hitKey
	 * @return
	 */
	@Lock(LockType.READ)
	public AtomicInteger getVote(CacheKey cacheKey) {
		AtomicInteger voteValue = VOTE_CACHE.get(cacheKey);
		if (voteValue == null) {
			int votes = getIntialVote(cacheKey);
			VOTE_CACHE.put(cacheKey, new AtomicInteger(votes));
		}
		return VOTE_CACHE.get(cacheKey);
	}

	/*
	 * @Lock(LockType.READ)
	 * public AtomicInteger getRating(int id) {
	 * CacheKey cacheKey = new CacheKey(id, CacheType.THREAD);
	 * AtomicInteger ratingValue = RATING_CACHE.get(cacheKey);
	 * if (ratingValue == null) {
	 * int rating = getInitialRating(cacheKey);
	 * RATING_CACHE.put(cacheKey, new AtomicInteger(rating));
	 * }
	 * return RATING_CACHE.get(cacheKey);
	 * }
	 */

	/**
	 * get intial hits from the db
	 */
	@Lock(LockType.READ)
	protected int getIntialVote(CacheKey cacheKey) {
		return hitManager.getVotes(cacheKey);
	}

	/*
	 * @Lock(LockType.READ)
	 * protected int getInitialRating(CacheKey cacheKey) {
	 * return hitManager.getRatings(cacheKey);
	 * }
	 */
	/**
	 * write it to db
	 */
	@SuppressWarnings("unused")
	@Timeout
	@Schedule(dayOfMonth = "*", month = "*", year = "*", second = "0", minute = "*/10", hour = "*")
	private void writeToDb() {//
		Set<CacheKey> voteKeySet = VOTE_CACHE.keySet();
		for (CacheKey hk : voteKeySet) {

			hitManager.updateVotes(hk, VOTE_CACHE.get(hk).intValue());

		}

		// clear the cache after writing it to the database
		VOTE_CACHE.clear();
		// RATING_CACHE.clear();

	}
	/* -------------getter/setter----------------- */
}
